home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / common / item.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  23KB  |  804 lines

  1. /*
  2.  * static char *rcsid_item_c =
  3.  *   "$Id: item.c,v 1.35 1996/07/24 07:01:37 master Exp master $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1992 Frank Tore Johansen
  10.  
  11.     This program is free software; you can redistribute it and/or modify
  12.     it under the terms of the GNU General Public License as published by
  13.     the Free Software Foundation; either version 2 of the License, or
  14.     (at your option) any later version.
  15.  
  16.     This program is distributed in the hope that it will be useful,
  17.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.     GNU General Public License for more details.
  20.  
  21.     You should have received a copy of the GNU General Public License
  22.     along with this program; if not, write to the Free Software
  23.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  
  25.     The author can be reached via e-mail to frankj@ifi.uio.no.
  26. */
  27.  
  28. #include <global.h>
  29. #include <funcpoint.h>
  30. #include <living.h>
  31.  
  32. #define    DESCRIBE_ABILITY(retbuf, variable, name) \
  33.     if(variable) { \
  34.       int i,j=0; \
  35.       strcat(retbuf,"(" name ": "); \
  36.       for(i=0; i<NROFATTACKS; i++) \
  37.         if(variable & (1<<i)) { \
  38.           if (j) \
  39.             strcat(retbuf,", "); \
  40.           else \
  41.             j = 1; \
  42.           strcat(retbuf, attacks[i]); \
  43.         } \
  44.       strcat(retbuf,")"); \
  45.     }
  46.  
  47. extern char *spellpathnames[NRSPELLPATHS];
  48.  
  49. static char numbers[21][20] = {
  50.   "no","a","two","three","four","five","six","seven","eight","nine","ten",
  51.   "eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen",
  52.   "eighteen","nineteen","twenty"
  53. };
  54.  
  55. static char numbers_10[10][20] = {
  56.   "zero","ten","twenty","thirty","fourty","fifty","sixty","seventy",
  57.   "eighty","ninety"
  58. };
  59.  
  60. static char levelnumbers[21][20] = {
  61.   "zeroth","first", "second", "third", "fourth", "fifth", "sixth", "seventh",
  62.   "eighth", "ninth", "tenth", "eleventh", "twelfth", "thirteenth",
  63.   "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteen",
  64.   "nineteen", "twentieth"
  65. };
  66.  
  67. static char levelnumbers_10[11][20] = {
  68.   "zeroth","tenth","twentieth","thirtieth","fortieth","fiftieth","sixtieth",
  69.   "seventieth","eightieth","ninetieth"
  70. };
  71.  
  72. extern spell spells[NROFREALSPELLS];
  73.  
  74. /*
  75.  * query_weight(object) returns a character pointer to a static buffer
  76.  * containing the text-representation of the weight of the given object.
  77.  * The buffer will be overwritten by the next call to query_weight().
  78.  */
  79.  
  80. char *query_weight(object *op) {
  81.   static char buf[10];
  82.   int i=op->nrof?op->nrof*op->weight:op->weight+op->carrying;
  83.  
  84.   if(op->weight<0)
  85.     return "      ";
  86.   if(i%1000)
  87.     sprintf(buf,"%6.1f",i/1000.0);
  88.   else
  89.     sprintf(buf,"%4d  ",i/1000);
  90.   return buf;
  91. }
  92.  
  93. /*
  94.  * Returns the pointer to a static buffer containing
  95.  * the number requested (of the form first, second, third...)
  96.  */
  97.  
  98. char *get_levelnumber(int i) {
  99.   static char buf[MAX_BUF];
  100.   if (i > 99) {
  101.     sprintf(buf, "%d.", i);
  102.     return buf;
  103.   }
  104.   if(i < 21)
  105.     return levelnumbers[i];
  106.   if(!(i%10))
  107.     return levelnumbers_10[i/10];
  108.   strcpy(buf, numbers_10[i/10]);
  109.   strcat(buf, levelnumbers[i%10]);
  110.   return buf;
  111. }
  112.  
  113.  
  114. /*
  115.  * get_number(integer) returns the text-representation of the given number
  116.  * in a static buffer.  The buffer might be overwritten at the next
  117.  * call to get_number().
  118.  * It is currently only used by the query_name() function.
  119.  */
  120.  
  121. char *get_number(int i) {
  122.   if(i<=20)
  123.     return numbers[i];
  124.   else {
  125.     static char buf[MAX_BUF];
  126.     sprintf(buf,"%d",i);
  127.     return buf;
  128.   }
  129. }
  130.  
  131. /*
  132.  *  Returns pointer to static buffer containing ring's or amulet's
  133.  *  abilities
  134.  *  These are taken from old query_name(), but it would work better
  135.  *  if describle_item() would be called to get this information and
  136.  *  caller would handle FULL_RING_DESCRIPTION definition.
  137.  *  Or make FULL_RING_DESCRIPTION standard part of a game and let
  138.  *  client handle names.
  139.  */
  140. /* Aug 95 modified this slightly so that Skill tools don't have magic bonus
  141.  * from stats.sp - b.t.
  142.  */
  143. char *ring_desc (object *op) 
  144. {
  145.     static char buf[MAX_BUF];
  146.     int attr, val;
  147.     
  148.     buf[0] = 0;
  149.  
  150.     if (! QUERY_FLAG(op, FLAG_IDENTIFIED))
  151.     return buf;
  152.  
  153.     for (attr=0; attr<7; attr++) {
  154.     if ((val=get_attr_value(&(op->stats),attr))!=0) {
  155.         sprintf (buf+strlen(buf), "(%s%+d)", short_stat_name[attr], val);
  156.     }
  157.     }
  158.     if(op->stats.exp)
  159.     sprintf(buf+strlen(buf), "(speed %+d)", op->stats.exp);
  160.     if(op->stats.wc)
  161.     sprintf(buf+strlen(buf), "(wc%+d)", op->stats.wc);
  162.     if(op->stats.dam)
  163.     sprintf(buf+strlen(buf), "(dam%+d)", op->stats.dam);
  164.     if(op->stats.ac)
  165.     sprintf(buf+strlen(buf), "(ac%+d)", op->stats.ac);
  166.     if(op->armour)
  167.     sprintf(buf+strlen(buf), "(armour%+d)", op->armour);
  168.     if (op->stats.food > 0)
  169.     sprintf(buf+strlen(buf), "(sustenance%+d)", op->stats.food);
  170.     else if (op->stats.food < 0)
  171.     sprintf(buf+strlen(buf), "(hunger%+d)", op->stats.food);
  172.     if(op->stats.sp && op->type!=SKILL)
  173.     sprintf(buf+strlen(buf), "(magic%+d)", op->stats.sp);
  174.     if(op->stats.hp)
  175.     sprintf(buf+strlen(buf), "(regeneration%+d)", op->stats.hp);
  176.     if(op->stats.luck)
  177.     sprintf(buf+strlen(buf), "(luck%+d)", op->stats.luck);
  178.     if(QUERY_FLAG(op,FLAG_LIFESAVE))
  179.     strcat(buf,"(lifesaving)");
  180.     if(QUERY_FLAG(op,FLAG_REFL_SPELL))
  181.     strcat(buf,"(reflect spells)");
  182.     if(QUERY_FLAG(op,FLAG_REFL_MISSILE))
  183.     strcat(buf,"(reflect missiles)");
  184.     if(QUERY_FLAG(op,FLAG_STEALTH))
  185.     strcat(buf,"(stealth)");
  186.     /* Shorten some of the names, so they appear better in the windows */
  187.     DESCRIBE_ABILITY(buf, op->immune, "Immune");
  188.     DESCRIBE_ABILITY(buf, op->protected, "Pro");
  189.     DESCRIBE_ABILITY(buf, op->vulnerable, "Vuln");
  190.     DESCRIBE_PATH(buf, op->path_attuned, "Attuned");
  191.     DESCRIBE_PATH(buf, op->path_repelled, "Repelled");
  192.     DESCRIBE_PATH(buf, op->path_denied, "Denied");
  193.     if(buf[0] == 0 && op->type!=SKILL)
  194.     strcpy(buf,"of adornment");
  195.     return buf;
  196. }
  197.  
  198. /*
  199.  * query_short_name(object) is similar to query_name, but doesn't 
  200.  * contain any information about object status (worn/cursed/etc.)
  201.  */
  202. char *query_short_name(object *op) 
  203. {
  204.     static char buf[MAX_BUF];
  205.     char buf2[MAX_BUF];
  206.  
  207.     if(op->name == NULL)
  208.     return "(null)";
  209.     if(!op->nrof && !op->weight && !op->title && !is_magical(op)) 
  210.     return op->name; /* To speed things up (or make things slower?) */
  211.     if(op->nrof) {
  212.     strcpy(buf, get_number(op->nrof));
  213.  
  214.     /* if nrof==1, then get_number returns 'a'. Add an 'n' if appropriate*/
  215.     if(op->nrof==1&&QUERY_FLAG(op,FLAG_AN))
  216.         strcat(buf,"n");
  217.  
  218.     strcat(buf, " ");
  219.     strcat(buf,op->name);
  220.     if (op->nrof != 1) {
  221.         char *buf3 = strstr(buf, " of ");
  222.         if (buf3!=NULL) {
  223.         strcpy(buf2, buf3);
  224.         *buf3 = '\0';    /* also changes value in buf */
  225.         }
  226.         if(QUERY_FLAG(op,FLAG_NEED_IE)) {
  227.         char *cp=strrchr(buf,'y');
  228.  
  229.         if(cp!=NULL)
  230.             *cp='\0'; /* Strip the 'y' */
  231.         strcat(buf,"ies");
  232.         } else if (buf[strlen(buf)-1]!='s') 
  233.         /* if the item ends in 's', then adding another one is 
  234.          * not the way to pluralize it.  The only item where this 
  235.          * matters (that I know of) is bracers, as they start of 
  236.          * plural 
  237.          */
  238.         strcat(buf,"s");
  239.  
  240.         /* If buf3 is set, then this was a string that contained
  241.          * something of something (potion of dexterity.)  The part before
  242.          * the of gets made plural, so now we need to copy the rest
  243.          * (after and including the " of "), to the buffer string.
  244.          */
  245.         if (buf3)
  246.         strcat(buf, buf2);
  247.     }
  248.     } else {
  249.     /* if nrof is 0, the object is not mergable, and thus, op->name
  250.        should contain the name to be used. */
  251.     strcpy(buf,op->name);
  252.     }
  253.     if (op->title && QUERY_FLAG(op,FLAG_IDENTIFIED)) {
  254.     strcat(buf, " ");
  255.     strcat(buf, op->title);
  256.     }
  257.  
  258.     switch(op->type) {
  259.       case SCROLL:
  260.       case WAND:
  261.       case SPELLBOOK:
  262.       case ROD:
  263.     if (QUERY_FLAG(op,FLAG_IDENTIFIED)||QUERY_FLAG(op,FLAG_BEEN_APPLIED)) {
  264.         if(!op->title) {
  265.         strcat(buf," of ");
  266.         strcat(buf,spells[op->stats.sp].name);
  267.         if(op->type != SPELLBOOK)
  268.             sprintf(buf+strlen(buf), " (lvl %d)", op->level);
  269.         }
  270.     }
  271.     break;
  272.  
  273.       case SKILL:
  274.       case AMULET:
  275.       case RING:
  276. #ifdef FULL_RING_DESCRIPTION
  277.     if (!op->title) {
  278.         /* If ring has a title, full description isn't so useful */ 
  279.         char *s = ring_desc(op);
  280.         if (s[0]) {
  281.         strcat (buf, " ");
  282.         strcat (buf, s);
  283.         }
  284.     }
  285. #endif
  286.     break;
  287.       default:
  288.     if(op->magic && ((QUERY_FLAG(op,FLAG_BEEN_APPLIED) && 
  289.        need_identify(op)) || QUERY_FLAG(op,FLAG_IDENTIFIED))) {
  290.         sprintf(buf + strlen(buf), " %+d", op->magic);
  291.     }
  292.     }
  293.     return buf;
  294. }
  295.  
  296. /*
  297.  * query_name(object) returns a character pointer pointing to a static
  298.  * buffer which contains a verbose textual representation of the name
  299.  * of the given object.  The buffer will be overwritten at the next
  300.  * call to query_name().
  301.  */
  302. char *query_name(object *op) {
  303.     static char buf[MAX_BUF];
  304.  
  305.     strcpy (buf, query_short_name(op));
  306.  
  307.     if (QUERY_FLAG(op,FLAG_INV_LOCKED))
  308.     strcat(buf, " *");
  309.     if (op->type == CONTAINER && ((op->env && op->env->container == op) || 
  310.     (!op->env && QUERY_FLAG(op,FLAG_APPLIED))))
  311.     strcat(buf," (open)");
  312.  
  313.     if (QUERY_FLAG(op,FLAG_KNOWN_CURSED)) {
  314.     if(QUERY_FLAG(op,FLAG_DAMNED))
  315.         strcat(buf, " (damned)");
  316.     else if(QUERY_FLAG(op,FLAG_CURSED))
  317.         strcat(buf, " (cursed)");
  318.     }
  319.     /* Basically, if the object is known magical (detect magic spell on it),
  320.      * and it isn't identified,  print out the fact that
  321.      * it is magical.  Assume that the detect magical spell will only set
  322.      * KNOWN_MAGICAL if the item actually is magical.
  323.      *
  324.      * Changed in V 0.91.4 - still print that the object is magical even
  325.      * if it has been applied.  Equipping an item does not tell full
  326.      * abilities, especially for artifact items.
  327.      */
  328.     if (QUERY_FLAG(op,FLAG_KNOWN_MAGICAL) && !QUERY_FLAG(op,FLAG_IDENTIFIED))
  329.     strcat(buf, " (magic)");
  330.     if(QUERY_FLAG(op,FLAG_APPLIED)) {
  331.     switch(op->type) {
  332.       case BOW:
  333.       case WAND:
  334.       case ROD:
  335.       case HORN:
  336.         strcat(buf," (readied)");
  337.         break;
  338.       case WEAPON:
  339.         strcat(buf," (wielded)");
  340.         break;
  341.       case ARMOUR:
  342.       case HELMET:
  343.       case SHIELD:
  344.       case RING:
  345.       case BOOTS:
  346.       case GLOVES:
  347.       case AMULET:
  348.       case GIRDLE:
  349.       case BRACERS:
  350.       case CLOAK:
  351.         strcat(buf," (worn)");
  352.         break;
  353.       case CONTAINER:
  354.         strcat(buf," (active)");
  355.         break;
  356.       case SKILL:
  357.       default:
  358.         strcat(buf," (applied)");
  359.     }
  360.     }
  361.     if(QUERY_FLAG(op, FLAG_UNPAID))
  362.     strcat(buf," (unpaid)");
  363.  
  364.     return buf;
  365. }
  366.  
  367. /*
  368.  * Returns a pointer to a static buffer which contains a
  369.  * description of the given object.
  370.  * If it is a monster, lots of information about its abilities
  371.  * will be returned.
  372.  * If it is an item, lots of information about which abilities
  373.  * will be gained about its user will be returned.
  374.  * If it is a player, it writes out the current abilities
  375.  * of the player, which is usually gained by the items applied.
  376.  */
  377.  
  378. char *describe_item(object *op) {
  379.   char buf[MAX_BUF];
  380.   static char retbuf[VERY_BIG_BUF];
  381.  
  382.   retbuf[0]='\0';
  383.   if(QUERY_FLAG(op,FLAG_MONSTER)) {
  384.     /* Merge:  Should it be 0.01 instead of 0.001? CE 0.7 has the former*/
  385.     if(FABS(op->speed)>0.001) {
  386.       switch((int)((FABS(op->speed))*15)) {
  387.       case 0:
  388.         strcat(retbuf,"(very slow movement)");
  389.         break;
  390.       case 1:
  391.         strcat(retbuf,"(slow movement)");
  392.         break;
  393.       case 2:
  394.         strcat(retbuf,"(normal movement)");
  395.         break;
  396.       case 3:
  397.       case 4:
  398.         strcat(retbuf,"(fast movement)");
  399.         break;
  400.       case 5:
  401.       case 6:
  402.         strcat(retbuf,"(very fast movement)");
  403.         break;
  404.       case 7:
  405.       case 8:
  406.       case 9:
  407.       case 10:
  408.         strcat(retbuf,"(extremely fast movement)");
  409.         break;
  410.       default:
  411.         strcat(retbuf,"(lightning fast movement)");
  412.         break;
  413.       }
  414.     }
  415.   } else switch(op->type) {
  416.     case BOW:
  417.     case ARROW:
  418.     case WAND:
  419.     case ROD:
  420.     case HORN:
  421.     case PLAYER:
  422.     case WEAPON:
  423.     case ARMOUR:
  424.     case HELMET:
  425.     case SHIELD:
  426.     case BOOTS:
  427.     case GLOVES:
  428.     case GIRDLE:
  429.     case BRACERS:
  430.     case CLOAK:
  431.       break;
  432.     case SKILL:
  433.     case RING:
  434.     case AMULET:
  435. #ifdef FULL_RING_DESCRIPTION
  436.       if (op->title)
  437.     strcat (retbuf, ring_desc(op));
  438. #else
  439.       strcat (retbuf, ring_desc(op));
  440. #endif
  441.       return retbuf;
  442.  
  443.     default:
  444.       return retbuf;
  445.     }
  446.   if(op->type!=PLAYER && !QUERY_FLAG(op,FLAG_MONSTER)) {
  447.     if(!need_identify(op) || QUERY_FLAG(op,FLAG_IDENTIFIED) || QUERY_FLAG(op,FLAG_BEEN_APPLIED)) {
  448.  
  449.       int attr,val;
  450.  
  451.       for (attr=0; attr<7; attr++) {
  452.         if ((val=get_attr_value(&(op->stats),attr))!=0) {
  453.           sprintf(buf, "(%s%+d)", short_stat_name[attr], val);
  454.           strcat(retbuf,buf);
  455.           }
  456.       }
  457.  
  458.       if(op->stats.exp) {
  459.         sprintf(buf,"(speed %+d)",op->stats.exp);
  460.         strcat(retbuf,buf);
  461.       }
  462.       switch(op->type) {
  463.       case BOW:
  464.       case ARROW:
  465.       case GIRDLE:
  466.       case HELMET:
  467.       case SHIELD:
  468.       case BOOTS:
  469.       case GLOVES:
  470.       case WEAPON:
  471.       case SKILL:
  472.       case RING:
  473.       case AMULET:
  474.       case ARMOUR:
  475.       case BRACERS:
  476.       case FORCE:
  477.       case CLOAK:
  478.         if(op->stats.wc) {
  479.           sprintf(buf,"(wc%+d)",op->stats.wc);
  480.           strcat(retbuf,buf);
  481.         }
  482.         if(op->stats.dam) {
  483.           sprintf(buf,"(dam%+d)",op->stats.dam);
  484.           strcat(retbuf,buf);
  485.         }
  486.         if(op->stats.ac) {
  487.           sprintf(buf,"(ac%+d)",op->stats.ac);
  488.           strcat(retbuf,buf);
  489.         }
  490.         break;
  491.       default:
  492.         break;
  493.       }
  494.     }
  495.     if(!need_identify(op) || QUERY_FLAG(op,FLAG_IDENTIFIED)) {
  496.       switch(op->type) {
  497.         case ROD:  /* These use stats.sp for spell selection and stats.food */
  498.         case HORN: /* and stats.hp for spell-point regeneration... */
  499.         case BOW:
  500.         case ARROW:
  501.         case WAND:
  502.           break;
  503.         default:
  504.           if(op->stats.food) {
  505.             if(op->stats.food>0)
  506.               sprintf(buf,"(sustenance%+d)",op->stats.food);
  507.             else
  508.               sprintf(buf,"(hunger%+d)",op->stats.food);
  509.             strcat(retbuf,buf);
  510.           }
  511.           if(op->stats.sp) {
  512.             sprintf(buf,"(magic%+d)",op->stats.sp);
  513.             strcat(retbuf,buf);
  514.           }
  515.           if(op->stats.hp) {
  516.             sprintf(buf,"(regeneration%+d)",op->stats.hp);
  517.             strcat(retbuf,buf);
  518.           }
  519.       }
  520.     }
  521.   } else if(op->type == PLAYER) {
  522.     if(op->contr->digestion) {
  523.       if(op->contr->digestion>0)
  524.         sprintf(buf,"(sustenance%+d)",op->contr->digestion);
  525.       else
  526.         sprintf(buf,"(hunger%+d)",op->contr->digestion);
  527.       strcat(retbuf,buf);
  528.     }
  529.     if(op->contr->gen_sp) {
  530.       sprintf(buf,"(magic%+d)",op->contr->gen_sp);
  531.       strcat(retbuf,buf);
  532.     }
  533.     if(op->contr->gen_hp) {
  534.       sprintf(buf,"(regeneration%+d)",op->contr->gen_hp);
  535.       strcat(retbuf,buf);
  536.     }
  537.   }
  538.   if(!need_identify(op) || QUERY_FLAG(op,FLAG_IDENTIFIED) || QUERY_FLAG(op,FLAG_BEEN_APPLIED)) {
  539.     if(op->armour) {
  540.       sprintf(buf,"(armour%+d)",op->armour);
  541.       strcat(retbuf,buf);
  542.     }
  543.     if(QUERY_FLAG(op,FLAG_XRAYS))
  544.       strcat(retbuf,"(xray-vision)");
  545.     if(QUERY_FLAG(op,FLAG_FLYING))
  546.       strcat(retbuf,"(levitate)");
  547.     if(QUERY_FLAG(op,FLAG_SEE_IN_DARK))
  548.       strcat(retbuf,"(infravision)");
  549.   }
  550.   if(!need_identify(op) || QUERY_FLAG(op,FLAG_IDENTIFIED)) {
  551.     if(op->stats.luck) {
  552.       sprintf(buf,"(luck%+d)",op->stats.luck);
  553.       strcat(retbuf,buf);
  554.     }
  555.     if(QUERY_FLAG(op,FLAG_LIFESAVE))
  556.       strcat(retbuf,"(lifesaving)");
  557.     if(QUERY_FLAG(op,FLAG_REFL_SPELL))
  558.       strcat(retbuf,"(reflect spells)");
  559.     if(QUERY_FLAG(op,FLAG_REFL_MISSILE))
  560.       strcat(retbuf,"(reflect missiles)");
  561.     if(QUERY_FLAG(op,FLAG_STEALTH))
  562.       strcat(retbuf,"(stealth)");
  563.     if(op->slaying!=NULL) {
  564.       strcat(retbuf,"(slay ");
  565.       strcat(retbuf,op->slaying);
  566.       strcat(retbuf,")");
  567.     }
  568.   }
  569.   if(QUERY_FLAG(op,FLAG_MONSTER)) {
  570.     if(QUERY_FLAG(op,FLAG_UNDEAD))
  571.       strcat(retbuf,"(undead)");
  572.     if(QUERY_FLAG(op,FLAG_CAN_PASS_THRU))
  573.       strcat(retbuf,"(pass through doors)");
  574.     if(QUERY_FLAG(op,FLAG_SEE_INVISIBLE))
  575.       strcat(retbuf,"(see invisible)");
  576.     if(QUERY_FLAG(op,FLAG_USE_WEAPON))
  577.       strcat(retbuf,"(wield weapon)");
  578.     if(QUERY_FLAG(op,FLAG_USE_BOW))
  579.       strcat(retbuf,"(archer)");
  580.     if(QUERY_FLAG(op,FLAG_USE_ARMOUR))
  581.       strcat(retbuf,"(wear armour)");
  582.     if(QUERY_FLAG(op,FLAG_USE_RING))
  583.       strcat(retbuf,"(wear ring)");
  584.     if(QUERY_FLAG(op,FLAG_USE_SCROLL))
  585.       strcat(retbuf,"(read scroll)");
  586.     if(QUERY_FLAG(op,FLAG_USE_WAND))
  587.       strcat(retbuf,"(fire wand)");
  588.     if(QUERY_FLAG(op,FLAG_USE_ROD))
  589.       strcat(retbuf,"(use rod)");
  590.     if(QUERY_FLAG(op,FLAG_USE_HORN))
  591.       strcat(retbuf,"(use horn)");
  592.     if(QUERY_FLAG(op,FLAG_CAST_SPELL))
  593.       strcat(retbuf,"(spellcaster)");
  594.     if(QUERY_FLAG(op,FLAG_FRIENDLY))
  595.       strcat(retbuf,"(friendly)");
  596.     if(QUERY_FLAG(op,FLAG_UNAGGRESSIVE))
  597.       strcat(retbuf,"(unaggressive)");
  598.     if(QUERY_FLAG(op,FLAG_HITBACK))
  599.       strcat(retbuf,"(hitback)");
  600.     if(op->arch->randomitems != NULL) {
  601.       treasure *t;
  602.       int first = 1;
  603.       for(t=op->arch->randomitems->items; t != NULL; t=t->next)
  604.         if(t->item && (t->item->clone.type == ABILITY)) {
  605.           if(first) {
  606.             first = 0;
  607.             strcat(retbuf,"(Spell abilities:)");
  608.           }
  609.           strcat(retbuf,"(");
  610.           strcat(retbuf,t->item->clone.name);
  611.           strcat(retbuf,")");
  612.         }
  613.     }
  614.   }
  615.   if(!need_identify(op)||QUERY_FLAG(op,FLAG_IDENTIFIED)||
  616.      QUERY_FLAG(op,FLAG_MONSTER)) {
  617. /*    if (op->attacktype != 1)*/
  618.       DESCRIBE_ABILITY(retbuf, op->attacktype, "Attacks");
  619.       DESCRIBE_ABILITY(retbuf, op->immune, "Immune");
  620.       DESCRIBE_ABILITY(retbuf, op->protected, "Protected");
  621.       DESCRIBE_ABILITY(retbuf, op->vulnerable, "Vulnerable");
  622.       DESCRIBE_PATH(retbuf, op->path_attuned, "Attuned");
  623.       DESCRIBE_PATH(retbuf, op->path_repelled, "Repelled");
  624.       DESCRIBE_PATH(retbuf, op->path_denied, "Denied");
  625.   }
  626.   return retbuf;
  627. }
  628.  
  629. /* Return true if the item is magical.  A magical item is one that
  630.  * increases/decreases any abilities, provides protection, immunity,
  631.  * or vulnerability, has a generic magical bonus, or is an artifact.
  632.  * This function is used by detect_magic to determine if an item
  633.  * should be marked as magical.
  634.  */
  635.  
  636. int is_magical(object *op) {
  637.     int i;
  638.  
  639.     /* living creatures are considered non magical */
  640.  
  641.     if (QUERY_FLAG(op, FLAG_ALIVE)) return 0;
  642.  
  643.     /* This is a test for it being an artifact, as artifacts have titles
  644.      */
  645.     if (op->title!=NULL) return 1;
  646.  
  647.     /* Handle rings and amulets specially.  If they change any of these
  648.      * values, it means they are magical.
  649.      */
  650.     if ((op->type==AMULET || op->type==RING) && 
  651.         (op->stats.ac || op->stats.food || op->stats.exp || op->stats.dam ||
  652.         op->stats.wc || op->stats.sp || op->stats.hp || op->stats.luck))
  653.          return 1;
  654.  
  655.     /* Take care of polished shield and helmet of xray vision */
  656.  
  657.     if ((op->type==AMULET || op->type==SHIELD) && (QUERY_FLAG(op, FLAG_REFL_SPELL) ||
  658.         QUERY_FLAG(op, FLAG_REFL_MISSILE))) return 1;
  659.  
  660.     if (op->type==HELMET && QUERY_FLAG(op,FLAG_XRAYS)) return 1;
  661.  
  662.  
  663.     /* Potions, rods & boots are always magical.  Wands/staves are also magical,
  664.      * assuming they still have any charges left.
  665.      */
  666.     if (op->type==POTION || op->type==ROD || op->type==BOOTS ||
  667.         (op->type==WAND && op->stats.food)) return 1;
  668.  
  669.  
  670.     /* if something protects, immunes or vulnerables, it must be magical.
  671.      * power crystal, spellbooks, and scrolls are always magical.
  672.      */
  673.     if (op->immune || op->protected || op->vulnerable || op->magic ||
  674.         op->type==POWER_CRYSTAL || op->type==SPELLBOOK || op->type==SCROLL)
  675.         return 1;
  676.  
  677.     /* Check to see if it increases/decreases any stats */
  678.     for (i=0; i<7; i++) 
  679.         if (get_attr_value(&(op->stats),i)!=0) return 1;
  680.  
  681.     /* If it doesn't fall into any of the above categories, must
  682.      * be non magical.
  683.      */
  684.     return 0;
  685. }
  686.  
  687. int always_magical(object *op) {
  688.   switch(op->type) {
  689.   case RING:
  690.   case BRACERS:
  691.   case BOOTS: /* For now at least */
  692.   case GLOVES: /* ditto */
  693.   case AMULET:
  694.   case GIRDLE:
  695.   case ROD:
  696.   case SCROLL:
  697.   case SPELLBOOK:
  698.   case POTION:
  699.     return 1;
  700.   case WAND:
  701.     if (op->stats.food)
  702.       return 1;
  703.   }
  704.   return 0;
  705. }
  706.  
  707. /* need_identify returns true if the item should be identified.  This 
  708.  * function really should not exist - by default, any item not identified
  709.  * should need it.
  710.  */
  711.  
  712. int need_identify(object *op) {
  713.   switch(op->type) {
  714.   case RING:
  715.   case WAND:
  716.   case ROD:
  717.   case HORN:
  718.   case SCROLL:
  719.   case SKILL:
  720.   case SKILLSCROLL:
  721.   case SPELLBOOK:
  722.   case FOOD:
  723.   case POTION:
  724.   case BOW:
  725.   case ARROW:
  726.   case WEAPON:
  727.   case ARMOUR:
  728.   case SHIELD:
  729.   case HELMET:
  730.   case AMULET:
  731.   case BOOTS:
  732.   case GLOVES:
  733.   case BRACERS:
  734.   case GIRDLE:
  735.   case CONTAINER:
  736.   case DRINK:
  737.   case FLESH:
  738.   case INORGANIC:
  739.   case CLOSE_CON:
  740.   case CLOAK:
  741.   case GEM:
  742.   case POWER_CRYSTAL:
  743.     return 1;
  744.   }
  745. /* Try to track down some stuff that may show up here.  Thus, the
  746.  * archetype file can be updated, and this function removed.
  747.  */
  748. #if 0
  749.   LOG(llevDebug,"need_identify: %s does not need to be id'd\n", op->name);
  750. #endif
  751.   return 0;
  752. }
  753.  
  754.  
  755. /* 
  756.  *  Return the number of the spell that whose name passes the pasesed string
  757.  *  argument.   Return -1 if no such spell name match is found.
  758.  */
  759. int look_up_spell_name( char * spname ){
  760.    register int i;
  761.    for(i=0;i< NROFREALSPELLS;i++){
  762.       if( strcmp(spname, spells[i].name) == 0) return i;
  763.    }
  764.    return -1;
  765. }
  766.  
  767. /*
  768.  * Supposed to fix face-values as well here, but later.
  769.  */
  770.  
  771. void identify(object *op) {
  772.  
  773.   SET_FLAG(op,FLAG_IDENTIFIED);
  774.   CLEAR_FLAG(op, FLAG_KNOWN_MAGICAL);
  775.  
  776. /*
  777.  * We want autojoining of equal objects:
  778.  */
  779.   if (QUERY_FLAG(op,FLAG_CURSED) || QUERY_FLAG(op,FLAG_DAMNED))
  780.     SET_FLAG(op,FLAG_KNOWN_CURSED);
  781.  
  782.   if (op->type == POTION && op->arch != (archetype *) NULL) {
  783.       op->face = op->arch->clone.face;
  784.       free_string(op->name);
  785.       op->name = add_refcount(op->arch->clone.name);
  786.   } else if( op->type == SPELLBOOK && op->slaying != NULL){
  787.        if((op->stats.sp = look_up_spell_name( op->slaying )) <0 ){
  788.       char buf[256];
  789.           op->stats.sp = -1;  
  790.           sprintf(buf, "Spell forumla for %s", op->slaying);
  791.       if(op->name != NULL) 
  792.         free_string(op->name);
  793.       op->name = add_string(buf);
  794.        } else {
  795.          /* clear op->slaying since we no longer need it */
  796.          free_string(op->slaying);
  797.          op->slaying=NULL;
  798.        }
  799.   }
  800.  
  801.   if (op->map) /* The shop identifies items before they hit the ground */
  802.     update_object(op);
  803. }
  804.